package com.myd.threadsafe;

import java.util.Random;

/**
 * 测试线程的可见性
 * @Author:
 * @DateTime: 2024/12/22 17:20
 * @Description:
 */
public class Test02 {
    public static void main(String[] args) throws InterruptedException {
        MyTask task = new MyTask();
        new Thread(task).start();

        Thread.sleep(1000);
        //主线程1秒后取消子线程
        //主线程调用了cancel()方法
        task.cancel();
        /*
            可能会出现以下情况：
                在main线程中调用了task.cancel()方法，把task对象的toCancel变量修改为true
                可能存在子线程看不到main线程对toCancel做的修改，在子线程中toCancel变量一直为false
            导致子线程看不到main线程对toCancel变量更新的原因，可能是：
                1）JIT即时编译期可能会对run方法中while循环进行优化为：
                    if (!toCancel) {
                        while (true) {
                            if (doSomething()) {
                                //...
                            }
                        }
                    }
                    这种优化是为了提高代码的运行效率，避免重复读取 toCancel 变量，但可能会导致死循环

                2）可能与计算机的存储系统有关，假设分别有两个CPU内核运行 main 线程与子线程，
                运行子线程的CPU无法立即读取运行main线程CPU中的数据
                导致了一个线程对共享变量的更新对另一个线程不可见的问题

         */
    }

    //这个运行结果不确定，看看能不能把线程取消，也就是有可能是"任务被取消"，也有可能是"任务正常结束"
    static class MyTask implements Runnable {
        public boolean toCancel = false;

        //在run方法中不断地 toCancel 变量值，如果是 false 就循环
        @Override
        public void run() {
            while (!toCancel) {
                if (doSomething()) {
                    //...
                }
            }
            if (toCancel) {
                System.out.println("任务被取消");
            } else {
                System.out.println("任务正常结束");
            }
        }

        private boolean doSomething() {
            System.out.println("执行某个人物....");
            //模拟执行任务的时间
            try {
                Thread.sleep(new Random().nextInt(1000));
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            return true;
        }

        //在这里这个方法是被主线程调用了
        public void cancel() {
            toCancel = true;
            System.out.println("收到取消线程的消息");
        }
    }
}
